using Microsoft.EntityFrameworkCore;
using net_work.Common;
using net_work.Common.Request;
using net_work.Common.Result;
using net_work.Config;
using net_work.Data.DTO.Appr;
using net_work.Data.Entity.Appr;
using net_work.Data.Enum.Appr;
using net_work.Data.VO.Appr;
using net_work.IRepository.Appr;

namespace net_work.Repository.Appr;

public class ApprovalInstanceRepository(ApplicationDbContext dbContext, IUserContext userContext)
    : Repository<ApprovalInstance>(dbContext), IApprovalInstanceRepository
{
    private async Task<string> GenerateInstanceCodeAsync()
    {
        // 获取当前时间戳
        var now = DateTime.UtcNow.ToLocalTime();
        var datePart = now.ToString("yyyyMMddHHmmss");

        // 获取当天最大的 Code 序号
        var maxCodeToday = await dbContext.ApprovalInstances
            .Where(inst => inst.CreatedTime.Date == now.Date)
            .OrderByDescending(inst => inst.Code) // 按 Code 倒序排列
            .Select(inst => inst.Code)
            .FirstOrDefaultAsync();

        // 解析当天序号
        var sequence = 1;
        if (!string.IsNullOrEmpty(maxCodeToday))
        {
            var parts = maxCodeToday.Split('-');
            if (parts.Length == 2 && int.TryParse(parts[1], out var maxSequence))
            {
                sequence = maxSequence + 1;
            }
        }

        // 拼接 Code
        return $"{datePart}-{sequence:D3}";
    }


    public async Task<long> InsertAsync(ApprovalInstanceAddRequest approvalInstanceAddRequest)
    {
        var usedFlow = await dbContext.Flows.FindAsync(approvalInstanceAddRequest.FlowId);
        if (usedFlow == null)
        {
            return -1;
        }

        var hasOld = await (from flow in dbContext.Flows
            join inst in dbContext.ApprovalInstances on flow.Id equals inst.FlowId
            where inst.Status != InstanceStatus.Finish && inst.BusinessId == approvalInstanceAddRequest.BusinessId &&
                  flow.BusinessCode == usedFlow.BusinessCode && inst.DelFlag == '0' && flow.DelFlag == '0'
            select inst).AnyAsync();

        if (hasOld)
        {
            return -1;
        }

        var approvalInstance = new ApprovalInstance
        {
            Code = await GenerateInstanceCodeAsync(),
            Status = InstanceStatus.ToBegin,
            FlowId = approvalInstanceAddRequest.FlowId,
            BusinessId = approvalInstanceAddRequest.BusinessId,
            CurrentFlowNodeId = usedFlow.BeginFlowNodeId,
            Remark = approvalInstanceAddRequest.Remark
        };
        await dbContext.ApprovalInstances.AddAsync(approvalInstance);
        await dbContext.SaveChangesAsync();
        return approvalInstance.Id;
    }

    public async Task<bool> UpdateAsync(ApprovalInstanceUpdateRequest approvalInstanceUpdateRequest)
    {
        var approvalInstance = await dbContext.ApprovalInstances.FindAsync(approvalInstanceUpdateRequest.Id);
        if (approvalInstance == null)
        {
            return false;
        }

        approvalInstance.BeginTime = approvalInstanceUpdateRequest.BeginTime;
        approvalInstance.EndTime = approvalInstanceUpdateRequest.EndTime;
        approvalInstance.Status = approvalInstanceUpdateRequest.Status;
        approvalInstance.CurrentFlowNodeId = approvalInstanceUpdateRequest.CurrentFlowNodeId;
        approvalInstance.Remark = approvalInstanceUpdateRequest.Remark;

        return await dbContext.SaveChangesAsync() > 0;
    }

    public async Task<PagedResult<ApprovalInstanceWithHistoryResult>> GetListAsync(PagedRequest pagedRequest)
    {
        var query = from inst in dbContext.ApprovalInstances
            join flow in dbContext.Flows on inst.FlowId equals flow.Id
            select new ApprovalInstanceWithHistoryResult
            {
                Id = inst.Id,
                Code = inst.Code,
                BeginTime = inst.BeginTime,
                EndTime = inst.EndTime,
                Status = inst.Status,
                FlowId = inst.FlowId,
                FlowName = flow.Name,
                CurrentFlowNodeId = inst.CurrentFlowNodeId,
                BusinessId = inst.BusinessId,
                Remark = inst.Remark,
                CreatedBy = inst.CreatedBy,
                CreatedTime = inst.CreatedTime,
                UpdatedBy = inst.UpdatedBy,
                UpdatedTime = inst.UpdatedTime,
                DelFlag = inst.DelFlag,
            };

        // Step 1: 获取分页结果
        var pagedResult = await GetPagedQueryResultAsync(query, pagedRequest);

        // Step 2: 获取当前页的实例 ID 列表
        var instanceIds = pagedResult.Data.Select(ai => ai.Id).ToList();

        // Step 3: 查询审批历史记录及流程节点名称
        var historyQuery = from history in dbContext.ApprovalInstanceHistories
            join flowNode in dbContext.FlowNodes on history.FlowNodeId equals flowNode.Id
            where instanceIds.Contains(history.InstanceId) // 仅查询分页内的历史记录
            select new ApprovalInstanceHistoryResult
            {
                Id = history.Id,
                InstanceId = history.InstanceId,
                FlowNodeId = history.FlowNodeId,
                Result = history.Result,
                Content = history.Content,
                FlowNodeName = flowNode.Name,
                CreatedBy = history.CreatedBy,
                CreatedTime = history.CreatedTime,
                UpdatedBy = history.UpdatedBy,
                UpdatedTime = history.UpdatedTime,
                Remark = history.Remark,
                DelFlag = history.DelFlag
            };

        var historyList = await historyQuery.ToListAsync();

        // Step 4: 将历史记录分配到对应的实例
        var historyLookup = historyList.GroupBy(h => h.InstanceId).ToDictionary(g => g.Key, g => g.ToList());

        foreach (var approvalInstanceResult in pagedResult.Data)
        {
            approvalInstanceResult.HistoryList =
                historyLookup.TryGetValue(approvalInstanceResult.Id, out List<ApprovalInstanceHistoryResult>? value)
                    ? value
                    : [];
        }

        // Step 5: 返回结果
        return pagedResult;
    }

    public async Task<PagedResult<ApprovalInstanceToDoResult>> GetToDoListAsync(PagedRequest pagedRequest)
    {
        // 获取当前用户的 ID 和个人信息 ID
        var userId = userContext.UserId;
        var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);

        if (user == null)
        {
            throw new Exception("User not found");
        }

        var psnId = user.PsnId;

        var query = from inst in dbContext.ApprovalInstances
            join flow in dbContext.Flows on inst.FlowId equals flow.Id
            join node in dbContext.FlowNodes on inst.CurrentFlowNodeId equals node.Id
            where inst.Status == InstanceStatus.ToBegin || inst.Status == InstanceStatus.Running
                && ((node.ProcessingType == NodeProcessingType.Teacher &&
                     dbContext.Teachers.Any(t => t.Id == node.ProcessingId && t.PsnId == psnId)) ||
                    (node.ProcessingType == NodeProcessingType.Dept &&
                     dbContext.Departments.Any(d => d.Id == node.ProcessingId &&
                                                    dbContext.Teachers.Any(t =>
                                                        t.DepId == d.Id && t.PsnId == psnId))))
            select new ApprovalInstanceToDoResult
            {
                Id = inst.Id,
                Code = inst.Code,
                BeginTime = inst.BeginTime,
                EndTime = inst.EndTime,
                Status = inst.Status,
                FlowId = inst.FlowId,
                CurrentFlowNodeId = inst.CurrentFlowNodeId,
                BusinessId = inst.BusinessId,
                FlowName = flow.Name,
                Remark = inst.Remark,
                CreatedBy = inst.CreatedBy,
                CreatedTime = inst.CreatedTime,
                UpdatedBy = inst.UpdatedBy,
                UpdatedTime = inst.UpdatedTime,
                DelFlag = inst.DelFlag,
                CurrentFlowNode = node
            };

        return await GetPagedQueryResultAsync(query, pagedRequest);
    }

    public async Task<bool> Skip(long approvalInstanceId, bool skipResult)
    {
        var approvalInstance = await dbContext.ApprovalInstances.FindAsync(approvalInstanceId);
        if (approvalInstance == null)
        {
            return false;
        }

        var flowNode = await dbContext.FlowNodes.FindAsync(approvalInstance.CurrentFlowNodeId);
        if (flowNode == null)
        {
            return false;
        }

        if (approvalInstance.Status == InstanceStatus.ToBegin)
        {
            approvalInstance.Status = InstanceStatus.Running;
            approvalInstance.BeginTime = DateTime.Now.ToLocalTime();
        }

        if (skipResult)
        {
            if (flowNode.SuccessNodeId == -1)
            {
                approvalInstance.EndTime = DateTime.Now.ToLocalTime();
                approvalInstance.Status = InstanceStatus.Finish;
                approvalInstance.CurrentFlowNodeId = null;

                return await dbContext.SaveChangesAsync() > 0;
            }

            approvalInstance.CurrentFlowNodeId = flowNode.SuccessNodeId;
            return await dbContext.SaveChangesAsync() > 0;
        }

        if (flowNode.FailureNodeId == -1)
        {
            approvalInstance.EndTime = DateTime.Now.ToLocalTime();
            approvalInstance.Status = InstanceStatus.Finish;
            approvalInstance.CurrentFlowNodeId = null;

            return await dbContext.SaveChangesAsync() > 0;
        }

        approvalInstance.CurrentFlowNodeId = flowNode.FailureNodeId;
        return await dbContext.SaveChangesAsync() > 0;
    }
}